#include <stdio.h>

#include <pthread.h>

#include <stdlib.h>
#include<time.h>
#include<semaphore.h>

#define ARR_LENGTH 4

struct Misson{
    pthread_t thread;
    pthread_mutex_t mtx;
    pthread_cond_t cond;
    time_t arrive_time;
    clock_t arrive_clock;
    int predicted_running_time;
    int state;//1 is ready, 0 is running
    int* arg;
    int priority;
    int running_time;
};

int total_time = 0;

pthread_mutex_t main_mtx;

pthread_cond_t main_cond;

int main_state = 0;

void* runner(void* arg){
    struct Misson* misson = (struct Misson*) arg;


    pthread_mutex_lock(&(misson->mtx));

    

    while(misson->state == 1){
        pthread_cond_wait(&(misson->cond),&(misson->mtx));
    }
    printf("im %ld num is %d\n", pthread_self(), *(misson->arg));

    main_state = 0;
    misson->state = 2;

    time_t nowtime = time(NULL);
    clock_t nowclock = clock();

    total_time += nowclock-misson->arrive_clock + misson->running_time;


    pthread_cond_signal(&main_cond);
    pthread_mutex_unlock(&(misson->mtx));
}

void FCFS(struct Misson missons[]){
    //FCFS
    for(int i = 0; i < ARR_LENGTH ; ++ i){
        pthread_mutex_lock(&(missons[i].mtx));

        missons[i].state = 0;
        main_state = 1;
        pthread_cond_signal(&(missons[i].cond));

        while(main_state == 1)
            pthread_cond_wait(&(main_cond),&(missons[i].mtx));
        
        
        pthread_mutex_unlock(&(missons[i].mtx));
    }
}

void Priority(struct Misson missons[]){
    //Priority
    for(int i = 0; i < ARR_LENGTH ; ++ i){
        int max_pri_index = 0;
        int max_pri = 0;
        for(int j = 0; j < ARR_LENGTH  ;++ j ){
            
            if(missons[j].state != 1 || missons[j].arrive_time > time(NULL)){
                continue;
            }
            
            
            if(missons[j].priority >= max_pri){
                max_pri_index = j;
                max_pri = missons[j].priority;
            }
        }
        pthread_mutex_lock(&(missons[max_pri_index].mtx));

        missons[max_pri_index].state = 0;
        main_state = 1;
        printf("this priority is %d ", max_pri);
        pthread_cond_signal(&(missons[max_pri_index].cond));

        while(main_state == 1)
            pthread_cond_wait(&(main_cond),&(missons[max_pri_index].mtx));
        
        
        pthread_mutex_unlock(&(missons[max_pri_index].mtx));
    }
}

void SJF(struct Misson missons[]){
    //SJF
    for(int i = 0; i < ARR_LENGTH ; ++ i){
        int min_time_index = 0;
        int min_time = RAND_MAX;
        for(int j = 0; j < ARR_LENGTH  ;++ j ){
            
            if(missons[j].state != 1 || missons[j].arrive_time > time(NULL)){
                continue;
            }
            
            
            if(missons[j].running_time <= min_time){
                min_time_index = j;
                min_time = missons[j].priority;
            }
        }
        pthread_mutex_lock(&(missons[min_time_index].mtx));

        missons[min_time_index].state = 0;
        main_state = 1;
        printf("this running time is %d ", min_time);
        pthread_cond_signal(&(missons[min_time_index].cond));

        while(main_state == 1)
            pthread_cond_wait(&(main_cond),&(missons[min_time_index].mtx));
        
        
        pthread_mutex_unlock(&(missons[min_time_index].mtx));
    }
}



int main(int argc, char const *argv[])
{   

    
    pthread_cond_init(&main_cond, NULL);
  

    int arr[] = {0,1,2,3,4,5,6,7,8,9};

    struct Misson missons[ARR_LENGTH];

    

    for(int i = 0; i < ARR_LENGTH; ++ i){
        pthread_create(&(missons[i].thread), NULL,runner, missons + i);
        pthread_cond_init(&(missons[i].cond), NULL);
        pthread_mutex_init(&(missons[i].mtx), NULL);
        missons[i].arrive_time = time(NULL);
        missons[i].arrive_clock = clock();
        missons[i].state = 1;//ready
        missons[i].arg = arr+i;
        missons[i].priority = rand() % 25;
        missons[i].running_time = rand() % 135;
    }

    FCFS(missons);
    //SJF(missons);
    //Priority(missons);

    printf("totaltime %d avg time %g\n", total_time,total_time * 1.0 / ARR_LENGTH/CLOCKS_PER_SEC);

    
    return 0;
}
